package com.example.speedwaymanager;

import android.util.SparseArray;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

final class PointsComparator implements Comparator<CRider> {
    @Override
    public int compare(CRider r1, CRider r2) {
        return r1.get_matchStats().get_points()
                .compareTo(r2.get_matchStats().get_points());
    }
}

public class CMatch {
    private ArrayList<CTeam> _teams;
    private ArrayList<CHeat> _heats = new ArrayList<CHeat>();
    private CSchedule _schedule;
    private final static int kMaxHeatCount = 15;
    private final static int kRaceGates = 4;
    private int _currentHeat = 0;
    private SparseArray<CRider> _rider = new SparseArray<CRider>();

    public CMatch(ArrayList<CTeam> teams, CSchedule schedule) {
        _teams = teams;
        _schedule = schedule;
        createSquad(teams);
        matchNoToRider();
        setNumbers(schedule);
    }

    private void createSquad(ArrayList<CTeam> teams) {
        for (CTeam team : teams) {
            if (!team.is_isUser() || team.get_squad().isEmpty())
                team.createSquad();
            team.clearAllMatchPoints();
        }
    }

    private void setNumbers(CSchedule schedule) {
        for (int i = 0; i < kMaxHeatCount - 2; ++i) {
            ArrayList<CRider> riders = new ArrayList<CRider>();
            for (int j = 0; j < kRaceGates; ++j) {
                setNumbersAndAverages(schedule, riders, i, j);
            }
            CHeat heat = new CHeat();
            heat.addRiders(riders);
            _heats.add(heat);
        }
    }

    private void setNumbersAndAverages(CSchedule schedule, ArrayList<CRider> riders, int i, int j) {
        int number = schedule.get_heat().get(i).get_gates().get(j)._no;
        CRider rider;
        if (number > 8) {
            rider = setMatchAvg(number, 0, 9);
        } else {
            rider = setMatchAvg(number, 1, 1);
        }
        rider.get_matchStats().set_number(number);
        riders.add(rider);
    }

    private CRider setMatchAvg(int number, int team, int lessNumber) {
        CRider rider;
        rider = _teams.get(team).get_squad().get(number - lessNumber);
        rider.set_matchAvg(rider.get_avgHome());
        return rider;
    }

    private void matchNoToRider() {
        for (int number = 0; number < 7; ++number) {
            _rider.put(number + 1, _teams.get(1).get_squad().get(number));
        }
        for (int number = 0; number < 7; ++number) {
            _rider.put(number + 9, _teams.get(0).get_squad().get(number));
        }
    }

    public Boolean isTacticalAllowedCPU() {
        int diff = _teams.get(0).get_points() - _teams.get(1).get_points();
        return _currentHeat > 6 && _currentHeat < 15 && Math.abs(diff) > 5;
    }

    public Boolean isTacticalAllowedUser() {
        int diff = _teams.get(0).get_points() - _teams.get(1).get_points();
        return _currentHeat < 15 && Math.abs(diff) > 5;
    }

    private void replace(CRider rider1, CRider rider2) {
        rider1 = rider2;
        // TODO rider1._matchStats.addHeatPoints(0);
    }

    public CHeat peekNextHeat() {
        if ((_currentHeat + 1) <= kMaxHeatCount)
            return _heats.get(_currentHeat + 1);
        return null;
    }

    public void startNextHeat() {
        if (_currentHeat < _heats.size()) {
            _heats.get(_currentHeat++).run();
            // assign team points after heat
            for (CTeam team : _teams) {
                team.calculateTeamPoints();
            }
            if (_currentHeat == 13) {
                nominateToHeats14and15();
            }
            analyzeChangeRequest(_currentHeat);
        }
    }

    public ArrayList<CRider> getHeatResults(int heat) {
        if (_heats.get(heat).get_RaceCompleted())
            return _heats.get(heat).get_riders();
        else
            return null;
    }

    public boolean isMatchCompleted() {
        boolean completed = true;
        for (CHeat heat : _heats) {
            if (!heat.get_RaceCompleted())
                completed = false;
        }
        return completed;
    }

    /**
     * Creates heat 14 and 15 using points. Best 2 riders from each team advance
     * to 15th heat 3rd and 4th rider go to 14th heat.
     */
    private void nominateToHeats14and15() {
        for (CTeam _team : _teams) {
            Collections
                    .sort(_team.get_riders(), new PointsComparator());
            Collections.reverse(_team.get_riders());
        }
        nominateTo14();
        nominateTo15();
    }

    private void nominateTo14() {
        CHeat heat = new CHeat();
        ArrayList<CRider> riders = new ArrayList<CRider>();
        riders.add(_teams.get(1).get_riders().get(2)); // away 3rd
        riders.add(_teams.get(0).get_riders().get(2)); // home 3rd
        riders.add(_teams.get(1).get_riders().get(3)); // away 4th
        riders.add(_teams.get(0).get_riders().get(3)); // home 4th
        heat.addRiders(riders);
        _heats.add(heat);
        _schedule.get_heat().get(13).get_gates().get(0)._no = riders.get(0).get_number();
        _schedule.get_heat().get(13).get_gates().get(1)._no = riders.get(1).get_number();
        _schedule.get_heat().get(13).get_gates().get(2)._no = riders.get(2).get_number();
        _schedule.get_heat().get(13).get_gates().get(3)._no = riders.get(3).get_number();

    }

    private void nominateTo15() {
        CHeat heat = new CHeat();
        ArrayList<CRider> riders = new ArrayList<CRider>();
        riders.add(_teams.get(0).get_riders().get(0)); // home 1st
        riders.add(_teams.get(1).get_riders().get(0)); // away 1st
        riders.add(_teams.get(0).get_riders().get(1)); // home 2nd
        riders.add(_teams.get(1).get_riders().get(1)); // away 2nd
        heat.addRiders(riders);
        _heats.add(heat);
        _schedule.get_heat().get(14).get_gates().get(0)._no = riders.get(0).get_number();
        _schedule.get_heat().get(14).get_gates().get(1)._no = riders.get(1).get_number();
        _schedule.get_heat().get(14).get_gates().get(2)._no = riders.get(2).get_number();
        _schedule.get_heat().get(14).get_gates().get(3)._no = riders.get(3).get_number();
    }

    public ArrayList<CRider> getRidersOfTeamInHeat(int heat, CTeam team) {
        return _heats.get(heat).get_ridersOfTeam(team);
    }

    /**
     * @return the currentHeat
     */
    public int getCurrentHeat() {
        return _currentHeat;
    }

    /**
     * @return the currentHeat
     */
    public int get_LastHeat() {
        if (_currentHeat <= 0)
            return _currentHeat;
        else
            return _currentHeat - 1;
    }

    /**
     * @return the _heats
     */
    public ArrayList<CHeat> get_heats() {
        return _heats;
    }

    private void analyzeChangeRequest(int i) {
        if (isTacticalAllowedCPU()) {
            if (_teams.get(0).get_points() < _teams.get(1).get_points()) {
                if (!_teams.get(0).is_isUser()) {
                    _teams.get(0).get_coach().analyzeChangeRequest(i, this);
                }
            } else {
                if (!_teams.get(1).is_isUser()) {
                    _teams.get(1).get_coach().analyzeChangeRequest(i, this);
                }
            }
        }
    }

    /**
     * @return the _teams
     */
    public ArrayList<CTeam> get_teams() {
        return _teams;
    }

    /**
     * @return the _currentHeat
     */
    public int get_currentHeat() {
        return _currentHeat;
    }

    /**
     * @param _currentHeat the _currentHeat to set
     */
    public void set_currentHeat(int _currentHeat) {
        this._currentHeat = _currentHeat;
    }

    /**
     * @return the _schedule
     */
    public CSchedule get_schedule() {
        return _schedule;
    }

    /**
     * @return the _rider
     */
    public SparseArray<CRider> get_rider() {
        return _rider;
    }

}
